package com.hmall.search.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.hmall.api.client.ItemClient;
import com.hmall.api.dto.ItemDTO;
import com.hmall.api.dto.OrderDetailDTO;
import com.hmall.search.domain.po.ItemDoc;
import com.hmall.search.service.SyncItemDataToES;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHost;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.List;

/**
 * 实现商品数据同步到ES的功能，包括新增、更新和删除商品，以及批量更新库存
 * @author xiaopeng
 * @version 1.0
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class SynItemDataToESImpl implements SyncItemDataToES {

    // 用于调用商品服务的客户端
    private final ItemClient itemClient;

    // 与ES交互的客户端
    private final RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(
                    HttpHost.create("http://192.168.88.133:9200")
            )
    );

    /**
     * 同步数据到es：新增/更新商品
     *
     * @param id 商品ID
     * @throws IOException 当与ES通信发生错误时抛出
     */
    @Override
    public void insertOrUpdateById(Long id) {
        try {
            // 1.根据id查询商品,获取最新的商品信息
            ItemDTO item = itemClient.queryItemById(id);
            if (item == null) {
                log.info("商品{}不存在，同步到ES失败", id);
                return;
            }
            // 2.转换为文档类型
            ItemDoc itemDoc = BeanUtil.copyProperties(item, ItemDoc.class);
            // 3.将ItemDTO转json
            String doc = JSONUtil.toJsonStr(itemDoc);

            // 4.准备Request对象
            IndexRequest request = new IndexRequest("items").id(itemDoc.getId());
            // 5.准备Json文档
            request.source(doc, XContentType.JSON);
            // 6.发送请求
            client.index(request, RequestOptions.DEFAULT);

            log.info("新增/更新：商品{}同步到ES成功,更新商品信息:{}", id, doc);
        } catch (IOException e) {
            log.error("Failed to insert or update item with id: {}", id, e);
        } finally {
            // 关闭资源
            closeClient();
        }
    }

    /**
     * 删除商品
     *
     * @param id 商品ID
     * @throws IOException 当与ES通信发生错误时抛出
     */
    @Override
    public void deleteById(Long id) {
        try {
            // 1.准备Request，两个参数，第一个是索引库名，第二个是文档id
            DeleteRequest request = new DeleteRequest("items", String.valueOf(id));
            // 2.发送请求
            client.delete(request, RequestOptions.DEFAULT);
            log.info("删除：商品{}同步到ES成功", id);
        } catch (IOException e) {
            log.error("Failed to delete item with id: {}", id, e);
        } finally {
            // 关闭资源
            closeClient();
        }
    }

    /**
     * 批量更新库存
     *
     * @param ids 商品ID列表
     * @throws IOException 当与ES通信发生错误时抛出
     */
    @Override
    public void updateStock(List<Long> ids) {
        try {
            for (Long id : ids) {
                // 1.根据id查询商品,获取最新的商品信息
                ItemDTO itemDTO = itemClient.queryItemById(id);
                ItemDoc itemDoc = BeanUtil.copyProperties(itemDTO, ItemDoc.class);
                Integer newStock = itemDoc.getStock();

                // 2.准备Request
                UpdateRequest request = new UpdateRequest("items", itemDoc.getId());
                // 3.准备请求参数
                request.doc(
                        "stock", newStock
                );
                // 4.发送请求
                client.update(request, RequestOptions.DEFAULT);

                log.info("批量更新商品库存：商品{}同步到ES成功，结果：{}", id, newStock);
            }
        } catch (IOException e) {
            log.error("Failed to update stock for items: {}", ids, e);
        } finally {
            // 关闭资源
            closeClient();
        }
    }

    /**
     * 关闭RestHighLevelClient
     */
    private void closeClient() {
        try {
            if (client != null) {
                client.close();
            }
        } catch (IOException e) {
            log.error("Failed to close RestHighLevelClient", e);
        }
    }
}

